package com.cdeledu.java高并发核心编程;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class CLHLock implements Lock {
	/**
	 * 当前节点的线程本地变量
	 */
	private static ThreadLocal<Node> curNodeLocal = new ThreadLocal<>();
	/**
	 * CLHLock队列的尾部指针，使用AtomicReference，方便进行CAS操作
	 */
	private AtomicReference<Node> tail = new AtomicReference<>(null);

	public CLHLock() {
		// 设置尾部节点
		tail.getAndSet(Node.EMPTY);
	}

	// 加锁操作：将节点添加到等待队列的尾部
	@Override
	public void lock() {
		Node curNode = new Node(true, null);
		Node preNode = tail.get();
		// CAS自旋：将当前节点插入队列的尾部
		while (!tail.compareAndSet(preNode, curNode)) {
			preNode = tail.get();
		}
		// 设置前驱节点
		curNode.setPrevNode(preNode);

		// 自旋，监听前驱节点的locked变量，直到其值为false
		// 若前驱节点的locked状态为true，则表示前一个线程还在抢占或者占有锁
		while (curNode.getPrevNode().isLocked()) {
			// 让出CPU时间片，提高性能
			Thread.yield();
		}
		// 能执行到这里，说明当前线程获取到了锁
		// Thread加入抢锁队列之后，会在前驱节点上自旋：循环判断前驱节点的locked属性是否为false，如果为false就表示前驱节点释放了锁，当前线程抢占到锁
		// Thread抢到锁之后，它的locked属性一直为true，一直到临界区代码执行完，然后调用unlock()方法释放锁，释放之后其locked属性才为false
		// Print.tcfo("获取到了锁！！！");

		// 将当前节点缓存在线程本地变量中，释放锁会用到
		curNodeLocal.set(curNode);
	}

	// 释放锁
	@Override
	public void unlock() {
		Node curNode = curNodeLocal.get();
		curNode.setLocked(false);
		curNode.setPrevNode(null); // help for GC
		curNodeLocal.set(null); // 方便下一次抢锁
	}

	// 虚拟等待队列的节点
	static class Node {
		public Node(boolean locked, Node prevNode) {
			this.locked = locked;
			this.prevNode = prevNode;
		}

		// true：当前线程正在抢占锁，或者已经占有锁
		// false：当前线程已经释放锁，下一个线程可以占有锁了
		volatile boolean locked;

		// 前一个节点，需要监听其locked字段
		Node prevNode;

		// 空节点
		public static final Node EMPTY = new Node(false, null);

		public boolean isLocked() {
			return locked;
		}

		public void setLocked(boolean locked) {
			this.locked = locked;
		}

		public Node getPrevNode() {
			return prevNode;
		}

		public void setPrevNode(Node prevNode) {
			this.prevNode = prevNode;
		}

	}

	// 省略其他代码
	@Override
	public void lockInterruptibly() throws InterruptedException {

	}

	@Override
	public boolean tryLock() {
		return false;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return false;
	}

	@Override
	public Condition newCondition() {
		return null;
	}
}